package example.database;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import jssia.database.DatabasesEnum;
import jssia.database.RDBMS;
import jssia.database.mysql.constants.Collation;
import jssia.database.mysql.transactions.Transaction;
import jssia.database.mysql.transactions.TransactionManager;
import jssia.database.mysql.transactions.VoidTransaction;
import jssia.exceptions.DatabaseConnectionException;

public enum Databases implements DatabasesEnum {

    EXAMPLE (RDBMS.MYSQL, Collation.UTF8_GENERAL_CI);

    private final RDBMS rdbms;
    private final Collation collation;

    private String name;
    private String user;
    private String pass;
    private String connectionUrl;

    /**
     * <code>threadLocalConnection</code> simply serves to enforce that there can only be one
     * connection per database per thread.  Changing this to be a custom connection
     * pool and re-implementing the <code>getConnection()</code> method is fine.
     */
    private final ThreadLocal<Connection> threadLocalConnection = new ThreadLocal<Connection>() {
        @Override protected Connection initialValue() {
            Connection conn = null;
            try {
                conn = DriverManager.getConnection(connectionUrl+name, user, pass);
            } catch (SQLException e) {
                TransactionManager.printSQLException(e);
                throw new DatabaseConnectionException("Could not connect to database with the following settings '"
                        + connectionUrl + "' : '" + user + "' : '" + pass + "'");
            }

            return conn;
        }
    };

    private Databases(RDBMS rdbms, Collation collation) {
        this.rdbms = rdbms;
        this.collation = collation;
    }

    public Collation getCollation() {
        return collation;
    }

    public RDBMS getRdbms() {
        return rdbms;
    }

    public String getName() {
        return name;
    }

    public Connection getConnection() {
        return threadLocalConnection.get();
    }

    public <T> T executeTransaction(Transaction<T> t) {
        return TransactionManager.executeTransaction(getConnection(), t);
    }

    public void executeTransaction(VoidTransaction t) {
        TransactionManager.executeTransaction(getConnection(), t);
    }
}

